package com.ukefu.webim.web.handler.admin.channel;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ukefu.core.UKDataContext;
import com.ukefu.util.Base62;
import com.ukefu.util.Menu;
import com.ukefu.util.UKTools;
import com.ukefu.util.WeiXinReport;
import com.ukefu.webim.service.cache.CacheHelper;
import com.ukefu.webim.service.repository.AgentServiceRepository;
import com.ukefu.webim.service.repository.InstructionRepository;
import com.ukefu.webim.service.repository.OnlineUserRepository;
import com.ukefu.webim.service.repository.OrganRepository;
import com.ukefu.webim.service.repository.SNSAccountRepository;
import com.ukefu.webim.service.repository.SecretRepository;
import com.ukefu.webim.service.repository.ServiceAiRepository;
import com.ukefu.webim.service.repository.TemplateRepository;
import com.ukefu.webim.service.repository.UserRepository;
import com.ukefu.webim.service.repository.WeiXinMenuRepository;
import com.ukefu.webim.service.repository.WeiXinUserRepository;
import com.ukefu.webim.service.repository.WxMpEventRepository;
import com.ukefu.webim.util.server.message.SessionConfigItem;
import com.ukefu.webim.util.weixin.config.WechatMpConfiguration;
import com.ukefu.webim.util.weixin.config.WechatOpenConfiguration;
import com.ukefu.webim.util.weixin.config.WeiXinConfiguration;
import com.ukefu.webim.web.handler.Handler;
import com.ukefu.webim.web.model.AgentService;
import com.ukefu.webim.web.model.Instruction;
import com.ukefu.webim.web.model.SNSAccount;
import com.ukefu.webim.web.model.Secret;
import com.ukefu.webim.web.model.SysDic;
import com.ukefu.webim.web.model.SystemConfig;
import com.ukefu.webim.web.model.UKeFuDic;
import com.ukefu.webim.web.model.WeiXinMenu;
import com.ukefu.webim.web.model.WeiXinUser;

import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult;
import me.chanjar.weixin.mp.bean.material.WxMpMaterialNewsBatchGetResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;

/**
 *
 *
 */

@Controller
@RequestMapping("/admin/weixin")
public class WeiXinController extends Handler{
	
	@Autowired
	private SNSAccountRepository snsAccountRes;
	
	@Autowired
	private WeiXinUserRepository weiXinUserRes ;
	
	@Autowired
	private WxMpEventRepository wxMpEventRes ;
	
	@Autowired
	private InstructionRepository instructionRes;
	
	@Autowired
	private OnlineUserRepository onlineUserRes ;
	
	@Autowired
	private UserRepository userRes ;
	
	@Autowired
	private ServiceAiRepository serviceAiRes ;
	
	@Autowired
	private OrganRepository organRes ;
	
	@Autowired
	private SecretRepository secRes ;
	
	@Autowired
	private AgentServiceRepository agentServiceRes ;
	
	private WechatMpConfiguration mpconfig = WechatMpConfiguration.getInstance();

	@Autowired
	private TemplateRepository templateRes ;
	
	private ObjectMapper objectMapper = new ObjectMapper();
	

	@Autowired
	private WeiXinMenuRepository weiXinMenuRepository;
    @RequestMapping("/index")
    @Menu(type = "weixin" , subtype = "weixin")
    public ModelAndView index(ModelMap map , HttpServletRequest request , @Valid String execute) {
    	map.addAttribute("snsAccountList", snsAccountRes.findBySnstypeAndOrgi(UKDataContext.ChannelTypeEnum.WEIXIN.toString() , super.getOrgi(request),new PageRequest(super.getP(request), super.getPs(request)))) ;
    	List<Secret> secretConfig = secRes.findByOrgi(super.getOrgi(request)) ;
    	if(secretConfig!=null && secretConfig.size() > 0){
    		map.addAttribute("secret", secretConfig.get(0)) ;
    	}
    	if(!StringUtils.isBlank(execute) && execute.equals("false")){
    		map.addAttribute("execute", execute) ;
    	}
    	return request(super.createAdminTempletResponse("/admin/channel/weixin/index"));
    }
    
    @RequestMapping("/add")
    @Menu(type = "weixin" , subtype = "weixin")
    public ModelAndView add(ModelMap map , HttpServletRequest request) {
    	//保证唯一
    	String snsid = getSnsid();
    	map.addAttribute("snsid", snsid) ;
        return request(super.createRequestPageTempletResponse("/admin/channel/weixin/add"));
    }

    private String getSnsid(){
		String snsid = Base62.encode(UKTools.getUUID());
		SNSAccount snsAccount = snsAccountRes.findBySnsid(snsid) ;
		if(snsAccount != null){
			return snsid = getSnsid();
		}
		return snsid;
	}
    @RequestMapping("/save")
    @Menu(type = "admin" , subtype = "weixin")
    public ModelAndView save(HttpServletRequest request ,@Valid SNSAccount snsAccount) throws NoSuchAlgorithmException {
    	//微信配置 全数据库唯一
		int count = snsAccountRes.countByAppkey(snsAccount.getAppkey()) ;
    	//int count = snsAccountRes.countByAppkeyAndOrgi(snsAccount.getAppkey() , super.getOrgi(request)) ;
		int count1 = snsAccountRes.countBySnsid(snsAccount.getSnsid()) ;
		String msg = "";
    	if(count == 0 && count1 == 0 &&!StringUtils.isBlank(snsAccount.getAppkey()) && !StringUtils.isBlank(snsAccount.getSecret())){
    		snsAccount.setSecret(UKTools.encryption(snsAccount.getSecret()));
    		snsAccount.setOrgi(super.getOrgi(request));
    		snsAccount.setSnstype(UKDataContext.ChannelTypeEnum.WEIXIN.toString());
    		
    		snsAccountRes.save(snsAccount) ;
    		
    		mpconfig.createRouter(snsAccount) ;
		}else{
			msg = "sns_exit";
		}
    	return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/index.html?msg=" + msg));
    }
    
    @RequestMapping("/delete")
    @Menu(type = "weixin" , subtype = "delete")
    public ModelAndView delete(ModelMap map , HttpServletRequest request , @Valid String id  , @Valid String confirm) {
    	boolean execute = false ;
    	if(execute = UKTools.secConfirm(secRes, super.getOrgi(request), confirm)){
	    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
	    	if(snsAccountRes!=null){
	    		snsAccountRes.delete(snsAccount);
	    		List<WeiXinUser> userList = weiXinUserRes.findBySnsidAndOrgi(snsAccount.getSnsid(),snsAccount.getOrgi());
	    		if(userList != null && userList.size() > 0){
					weiXinUserRes.delete(userList);
				}
				Object object = CacheHelper.getSystemCacheBean().getCacheObject(snsAccount.getSnsid(), snsAccount.getOrgi());
				if(object != null){
					CacheHelper.getSystemCacheBean().delete(snsAccount.getSnsid(), snsAccount.getOrgi()) ;
				}
	    	}
    	}
    	
        return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/index.html?execute="+execute));
    }
    
    @RequestMapping("/edit")
    @Menu(type = "weixin" , subtype = "weixin")
    public ModelAndView edit(ModelMap map , HttpServletRequest request , @Valid String id) {
    	map.addAttribute("snsAccount", snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request))) ;
        return request(super.createRequestPageTempletResponse("/admin/channel/weixin/edit"));
    }
    
    @RequestMapping("/update")
    @Menu(type = "admin" , subtype = "weixin")
    public ModelAndView update(HttpServletRequest request ,@Valid SNSAccount snsAccount) throws NoSuchAlgorithmException {
    	SNSAccount oldSnsAccount = snsAccountRes.findByIdAndOrgi(snsAccount.getId() , super.getOrgi(request));
		int count = snsAccountRes.countByAppkeyAndIdNot(snsAccount.getAppkey(),snsAccount.getId()) ;
		int count1 = snsAccountRes.countBySnsidAndIdNot(snsAccount.getSnsid(),snsAccount.getId()) ;

		String msg = "";
    	if(oldSnsAccount!=null && count == 0 && count1 == 0 ){
    		if(!StringUtils.isBlank(snsAccount.getSecret())){
    			oldSnsAccount.setSecret(UKTools.encryption(snsAccount.getSecret()));
    		}
    		oldSnsAccount.setName(snsAccount.getName());


    		oldSnsAccount.setAppkey(snsAccount.getAppkey());
    		oldSnsAccount.setToken(snsAccount.getToken());
    		oldSnsAccount.setAeskey(snsAccount.getAeskey());
    		oldSnsAccount.setUpdatetime(new Date());
    		
    		
    		oldSnsAccount.setSnstype(UKDataContext.ChannelTypeEnum.WEIXIN.toString());
    		
    		snsAccountRes.save(oldSnsAccount) ;
    		
    		mpconfig.createRouter(oldSnsAccount) ;
		}else{
			msg = "sns_exit";
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/index.html?msg=" + msg));
    }
    
    @RequestMapping("/enable")
    @Menu(type = "admin" , subtype = "weixin")
    public ModelAndView enable(HttpServletRequest request ,@Valid String id) throws NoSuchAlgorithmException {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
    	if(snsAccount!=null){
    		snsAccount.setAgent(true);
    		snsAccountRes.save(snsAccount) ;
    		mpconfig.createRouter(snsAccount) ;
    	}
    	return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/detail.html?id="+id));
    }
    @RequestMapping("/disable")
    @Menu(type = "admin" , subtype = "weixin")
    public ModelAndView disable(HttpServletRequest request ,@Valid String id) throws NoSuchAlgorithmException {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
    	if(snsAccount!=null){
    		snsAccount.setAgent(false);
    		snsAccountRes.save(snsAccount) ;
    		mpconfig.createRouter(snsAccount) ;
    	}
    	return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/detail.html?id="+id));
    }
    
    @RequestMapping("/detail")
    @Menu(type = "weixin" , subtype = "weixin" , name = "detail")
    public ModelAndView detail(ModelMap map , HttpServletRequest request , @Valid String id) {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
    	map.addAttribute("snsAccount", snsAccount) ;
    	map.addAttribute("weiXinUserCount", weiXinUserRes.countBySnsidAndOrgi(snsAccount.getSnsid() , super.getOrgi(request))) ;
    	
    	WeiXinReport today = UKTools.getWeiXinReportResult(wxMpEventRes.findByOrgiAndCreatetimeRangeForClient(super.getOrgi(request) , snsAccount.getSnsid(), UKTools.getStartTime(), UKTools.getEndTime())) ;
    	WeiXinReport lastday = UKTools.getWeiXinReportResult(wxMpEventRes.findByOrgiAndCreatetimeRangeForClient(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(1), UKTools.getStartTime())) ;
    	WeiXinReport last7day = UKTools.getWeiXinReportResult(wxMpEventRes.findByOrgiAndCreatetimeRangeForClient(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(7), UKTools.getEndTime())) ;
    	WeiXinReport last30day = UKTools.getWeiXinReportResult(wxMpEventRes.findByOrgiAndCreatetimeRangeForClient(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(30), UKTools.getEndTime())) ;
    	
    	map.addAttribute("todayService", onlineUserRes.countByOrgiAndAppidForCount(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getStartTime(), UKTools.getEndTime())) ;
    	map.addAttribute("lastdayService", onlineUserRes.countByOrgiAndAppidForCount(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(1), UKTools.getStartTime())) ;
    	map.addAttribute("last7dayService", onlineUserRes.countByOrgiAndAppidForCount(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(7), UKTools.getEndTime())) ;
    	map.addAttribute("last30dayService", onlineUserRes.countByOrgiAndAppidForCount(super.getOrgi(request), snsAccount.getSnsid(), UKTools.getLastDay(30), UKTools.getEndTime())) ;
    	
    	map.addAttribute("today", today) ;
    	map.addAttribute("lastday", lastday) ;
    	map.addAttribute("last7day", last7day) ;
    	map.addAttribute("last30day", last30day) ;
    	
    	final String orgi = super.getOrgi(request);
    	Page<AgentService> agentServiceList = this.agentServiceRes.findAll(new Specification<AgentService>() {
			
			@Override
			public Predicate toPredicate(Root<AgentService> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> list = new ArrayList<Predicate>();  
				list.add(cb.equal(root.get("orgi").as(String.class), orgi));
				list.add(cb.equal(root.get("status").as(String.class), UKDataContext.AgentUserStatusEnum.INSERVICE.toString()));
				list.add(cb.equal(root.get("channel").as(String.class), UKDataContext.OnlineUserTypeStatus.WEIXIN.toString()));
				Predicate[] p = new Predicate[list.size()];  
				return cb.and(list.toArray(p));   
			}
		}, new PageRequest(0, super.get50Ps(request), Sort.Direction.DESC,new String[] {"createtime"}));
    	map.addAttribute("agentServiceList", agentServiceList);
    	map.addAttribute("userList", this.userRes.findByOrgiAndDatastatusAndOrgid(super.getOrgi(request), false, super.getOrgi(request)));
        return request(super.createAdminTempletResponse("/admin/channel/weixin/detail"));
    }
    
    @RequestMapping("/imr")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imr(ModelMap map , HttpServletRequest request , @Valid String id) {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
    	map.addAttribute("snsAccount", snsAccount) ;
    	
    	map.addAttribute("weiXinUserCount", weiXinUserRes.countBySnsidAndOrgi(snsAccount.getSnsid() , super.getOrgi(request))) ;
    	
    	map.addAttribute("instructionList", instructionRes.findBySnsidAndOrgi(snsAccount.getSnsid()  , super.getOrgi(request) , new PageRequest(super.getP(request), super.getPs(request)))) ;
    	
        return request(super.createAdminTempletResponse("/admin/channel/weixin/imr"));
    }
    
    @RequestMapping("/imr/add")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imradd(ModelMap map , HttpServletRequest request , @Valid String said) {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(said , super.getOrgi(request)) ;
    	map.addAttribute("snsAccount", snsAccount) ;
    	map.addAttribute("skillList", organRes.findByOrgiAndSkill(super.getOrgi(request), true) ) ;
    	
    	map.addAttribute("agentList", userRes.findByOrgiAndAgentAndDatastatus(super.getOrgi(request), true,false)) ;
    	
    	if(UKDataContext.model.get("xiaoe")!=null) {
    		map.addAttribute("serviceAiList", serviceAiRes.findByOrgi(super.getOrgi(request))) ;
    	}
        return request(super.createRequestPageTempletResponse("/admin/channel/weixin/imr/add"));
    }
    
    @RequestMapping("/imr/save")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imrsave(ModelMap map , HttpServletRequest request , @Valid Instruction instruction , @Valid String said) {
    	long count = instructionRes.countByNameAndSnsidAndOrgi(instruction.getName() , said, super.getOrgi(request)) ;
    	if(count == 0){
    		
    		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(said , super.getOrgi(request)) ;
    		instruction.setOrgi(super.getOrgi(request));
    		instruction.setSnsid(snsAccount.getSnsid());
    		
    		instructionRes.save(instruction) ;
    		
    		CacheHelper.getIMRCacheBean().put(instruction.getTopic(), instruction, super.getOrgi(request));
    	}
        return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/imr.html?id="+said));
    }
    
    @RequestMapping("/imr/edit")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imredit(ModelMap map , HttpServletRequest request , @Valid String id , @Valid String said) {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(said , super.getOrgi(request)) ;
    	map.addAttribute("snsAccount", snsAccount) ;
    	map.addAttribute("ins", instructionRes.findByIdAndOrgi(id , super.getOrgi(request))) ;
    	
    	map.addAttribute("skillList", organRes.findByOrgiAndSkill(super.getOrgi(request), true) ) ;
    	map.addAttribute("agentList", userRes.findByOrgiAndAgentAndDatastatus(super.getOrgi(request), true,false)) ;
    	
    	if(UKDataContext.model.get("xiaoe")!=null) {
    		map.addAttribute("serviceAiList", serviceAiRes.findByOrgi(super.getOrgi(request))) ;
    	}
    	
        return request(super.createRequestPageTempletResponse("/admin/channel/weixin/imr/edit"));
    }
    
    @RequestMapping("/imr/update")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imrupdate(ModelMap map , HttpServletRequest request , @Valid Instruction instruction , @Valid String said) {
    	long count = instructionRes.countByNameAndSnsidAndOrgiAndIdNot(instruction.getName() , said , super.getOrgi(request), instruction.getId()) ;
    	if(count == 0){
    		
    		Instruction oldIns = instructionRes.findByIdAndOrgi(instruction.getId() , super.getOrgi(request)) ;
    		CacheHelper.getIMRCacheBean().delete(oldIns.getTopic(), super.getOrgi(request)) ;
    		
    		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(said , super.getOrgi(request)) ;
    		instruction.setOrgi(super.getOrgi(request));
    		instruction.setSnsid(snsAccount.getSnsid());
    		instruction.setCreatetime(oldIns.getCreatetime());
    		instructionRes.save(instruction) ;
    		
    		CacheHelper.getIMRCacheBean().put(instruction.getTopic(), instruction, super.getOrgi(request));
    	}
        return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/imr.html?id="+said));
    }
    
    @RequestMapping("/imr/delete")
    @Menu(type = "weixin" , subtype = "weixin" , name = "imr")
    public ModelAndView imrdelete(ModelMap map , HttpServletRequest request , @Valid Instruction ins, @Valid String said) {
    	if(!StringUtils.isBlank(ins.getId())){
    		ins = instructionRes.findByIdAndOrgi(ins.getId() , super.getOrgi(request)) ;
    		if(ins!=null) {
	    		instructionRes.delete(ins);
	    		CacheHelper.getIMRCacheBean().delete(ins.getTopic(), super.getOrgi(request));
    		}
    	}
        return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/imr.html?id="+said));
    }
    
    @RequestMapping("/fans")
    @Menu(type = "weixin" , subtype = "weixin" , name = "fans")
    public ModelAndView fans(ModelMap map , HttpServletRequest request , @Valid String id) {
    	SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
    	map.addAttribute("snsAccount", snsAccount) ;
    	Page<WeiXinUser> weiXinUserList = weiXinUserRes.findByAppidAndOrgi(snsAccount.getAppkey(), super.getOrgi(request), new PageRequest(super.getP(request), super.getPs(request), Sort.Direction.DESC,"subscribetime"));
    	map.addAttribute("weiXinUserList", weiXinUserList) ;

    	long allCount = weiXinUserList.getTotalElements();
    	map.addAttribute("weiXinUserCount", allCount) ;
		long unSubscribeCount = weiXinUserRes.countBySnsidAndSubscribeAndOrgi(snsAccount.getSnsid() , false,super.getOrgi(request));
		map.addAttribute("unSubscribeCount",unSubscribeCount) ;
		map.addAttribute("subscribeCount",allCount - unSubscribeCount) ;
        return request(super.createAdminTempletResponse("/admin/channel/weixin/fans"));
    }


	@RequestMapping("/menu")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menu(ModelMap map , HttpServletRequest request , @Valid String id) {
		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;

		List<WeiXinMenu> parentList = weiXinMenuRepository.findBySnsidAndOrgiOrderBySortindexAsc(id,super.getOrgi(request));

		map.addAttribute("menuButtonType",UKDataContext.MenuButtonType.getMap());
		map.addAttribute("parentList", parentList) ;

		map.addAttribute("snsAccount", snsAccount) ;
		return request(super.createAdminTempletResponse("/admin/channel/weixin/menu"));
	}

	@RequestMapping("/menu/add")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuAdd(ModelMap map , HttpServletRequest request , @Valid String id) {
		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;

		map.addAttribute("menuButtonType",UKDataContext.MenuButtonType.getMap());

		map.addAttribute("snsAccount", snsAccount) ;

		map.addAttribute("menu", null) ;

		List<WeiXinMenu> parentList = weiXinMenuRepository.findBySnsidAndOrgiAndParentidOrderBySortindexAsc(id,super.getOrgi(request),"0");
		map.addAttribute("parentList", parentList) ;

		return request(super.createAdminTempletResponse("/admin/channel/weixin/menu/add"));
	}

	@RequestMapping("/menu/save")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menusave(ModelMap map , HttpServletRequest request , @Valid WeiXinMenu menu) {
		if(menu != null){
			if(StringUtils.isBlank(menu.getParentid())){
				menu.setParentid("0");//设置为父级
			}
			menu.setOrgi(super.getOrgi(request));
			menu.setCreater(super.getUser(request).getId());

			weiXinMenuRepository.save(menu) ;

		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+menu.getSnsid()));
	}

	@RequestMapping("/menu/edit")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuEdit(ModelMap map , HttpServletRequest request , @Valid String id) {
    	if(StringUtils.isNotBlank(id)){

    		WeiXinMenu menu = weiXinMenuRepository.findByIdAndOrgi(id,super.getOrgi(request));
			map.addAttribute("menu", menu) ;
			SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(menu.getSnsid() , super.getOrgi(request)) ;
			map.addAttribute("menuButtonType",UKDataContext.MenuButtonType.getMap());
			map.addAttribute("snsAccount", snsAccount) ;

			List<WeiXinMenu> parentList = weiXinMenuRepository.findBySnsidAndOrgiAndParentidOrderBySortindexAsc(menu.getSnsid(),super.getOrgi(request),"0");
			map.addAttribute("parentList", parentList) ;

		}
		return request(super.createAdminTempletResponse("/admin/channel/weixin/menu/edit"));
	}

	@RequestMapping("/menu/update")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuupdate(ModelMap map , HttpServletRequest request , @Valid WeiXinMenu menu) {
		if(menu != null){
			WeiXinMenu menuTemp = weiXinMenuRepository.findByIdAndOrgi(menu.getId(),super.getOrgi(request));

			if(StringUtils.isBlank(menu.getParentid())){
				menu.setParentid("0");//设置为父级
			}
			//选为他自己
			if(menu.getParentid().equals(menuTemp.getId())){
				menu.setParentid("0");//设置为父级
			}
			menu.setOrgi(menuTemp.getOrgi());
			menu.setSnsid(menuTemp.getSnsid());
			menu.setCreater(menuTemp.getCreater());
			menu.setCreatetime(menuTemp.getCreatetime());
			weiXinMenuRepository.save(menu) ;

		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+menu.getSnsid()));
	}
	@SuppressWarnings("null")
	@RequestMapping("/menu/delete")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menudelete(ModelMap map , HttpServletRequest request , @Valid WeiXinMenu menu) {
    	String msg = "";
		if(menu != null){
			WeiXinMenu menuTemp = weiXinMenuRepository.findByIdAndOrgi(menu.getId(),super.getOrgi(request));
			List<WeiXinMenu> subList = weiXinMenuRepository.findBySnsidAndOrgiAndParentidOrderBySortindexAsc(menuTemp.getSnsid(),super.getOrgi(request),menuTemp.getId());

			if(subList!=null && subList.size() > 0){
				msg = "exist_sub";
			}else{
				weiXinMenuRepository.delete(menuTemp); ;
			}
			return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+menuTemp.getSnsid()+"&msg="+ msg));
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+menu.getSnsid()+"&msg="+ msg));
	}

	@RequestMapping("/menu/getMedia")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuGetMedia(ModelMap map , HttpServletRequest request , @Valid String id,@Valid String type) {
		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;

		WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsAccount.getSnsid()) ;

		if(weiXinConfigure != null){
			try {
				if (StringUtils.isNotBlank(type)){
					if("news".equals(type)){
						WxMpMaterialNewsBatchGetResult result = weiXinConfigure.getService().getMaterialService().materialNewsBatchGet(super.getP(request)*super.getPs(request),super.getPs(request));
						if(result != null){
							map.addAttribute("totalCount",result.getTotalCount());
							map.addAttribute("items",result.getItems());
							map.addAttribute("curr",super.getP(request));
							map.addAttribute("totalPages",result.getTotalCount()/super.getPs(request) + 1);
						}
					}else{
						WxMpMaterialFileBatchGetResult result = weiXinConfigure.getService().getMaterialService().materialFileBatchGet(type,super.getP(request)*super.getPs(request),super.getPs(request));
						if(result != null){
							map.addAttribute("totalCount",result.getTotalCount());
							map.addAttribute("items",result.getItems());
							map.addAttribute("curr",super.getP(request));
							map.addAttribute("totalPages",result.getTotalCount()/super.getPs(request) + 1);
						}
					}
				}
			} catch (WxErrorException e) {
				e.printStackTrace();
			}
		}
		map.addAttribute("menuButtonType",UKDataContext.MenuButtonType.getMap());
		map.addAttribute("snsAccount", snsAccount) ;
		map.addAttribute("type", type) ;
		return request(super.createRequestPageTempletResponse("/admin/channel/weixin/menu/media"));
	}


	@RequestMapping("/menu/getMediaAjax")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuGetMediaAjax(ModelMap map , HttpServletRequest request , @Valid String id,@Valid String type) {
		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;

		WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsAccount.getSnsid()) ;

		if(weiXinConfigure != null){
			try {
				if (StringUtils.isNotBlank(type)){
					if("news".equals(type)){
						WxMpMaterialNewsBatchGetResult result = weiXinConfigure.getService().getMaterialService().materialNewsBatchGet(super.getP(request)*super.getPs(request),super.getPs(request));
						if(result != null){
							map.addAttribute("totalCount",result.getTotalCount());
							map.addAttribute("items",result.getItems());
							map.addAttribute("curr",super.getP(request));
							map.addAttribute("totalPages",result.getTotalCount()/super.getPs(request) + 1);
						}
					}else{
						WxMpMaterialFileBatchGetResult result = weiXinConfigure.getService().getMaterialService().materialFileBatchGet(type,super.getP(request)*super.getPs(request),super.getPs(request));
						if(result != null){
							map.addAttribute("totalCount",result.getTotalCount());
							map.addAttribute("items",result.getItems());
							map.addAttribute("curr",super.getP(request));
							map.addAttribute("totalPages",result.getTotalCount()/super.getPs(request) + 1);
						}
					}
				}
			} catch (WxErrorException e) {
				e.printStackTrace();
			}
		}
		map.addAttribute("menuButtonType",UKDataContext.MenuButtonType.getMap());

		map.addAttribute("snsAccount", snsAccount) ;
		map.addAttribute("type", type) ;

		return request(super.createRequestPageTempletResponse("/admin/channel/weixin/menu/mediaitem"));
	}

	@RequestMapping("/menu/valid")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menudvalid(ModelMap map , HttpServletRequest request , @Valid String id) {
		String msg = "valid_success";
		if(StringUtils.isNotBlank(id)){
			Map<String,Object> result = validPost(id,request);
			msg = (String)result.get("msg");
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+id+"&msg="+ msg));
	}

	/**
	 * 同步到微信
	 * @param map
	 * @param request
	 * @param id
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	@RequestMapping("/menu/post")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public ModelAndView menuPost(ModelMap map , HttpServletRequest request , @Valid String id) {
		String msg = "valid_success";
		if(StringUtils.isNotBlank(id)){
			SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
			Map<String,Object> result = validPost(id,request);
			msg = (String)result.get("msg");
			List<WeiXinMenu> list = (List<WeiXinMenu>)result.get("list");
			if("valid_success".equals(msg)){

				WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsAccount.getSnsid()) ;

				if(weiXinConfigure != null){
					WxMenu wxMenu = new WxMenu();
					List<WxMenuButton> buttons = wxMenu.getButtons();
					for(WeiXinMenu fMenu : list){
						WxMenuButton wxMenuButton = new WxMenuButton();
						wxMenuButton.setAppId(fMenu.getAppid());
						wxMenuButton.setKey(fMenu.getKeyv());
						wxMenuButton.setMediaId(fMenu.getMediaid());
						wxMenuButton.setName(fMenu.getName());
						wxMenuButton.setPagePath(fMenu.getPagepath());
						wxMenuButton.setType(fMenu.getType());
						wxMenuButton.setUrl(fMenu.getUrl());
						List<WxMenuButton> subbuttons = wxMenuButton.getSubButtons();
						for(WeiXinMenu sMenu : fMenu.getSubList()){
							WxMenuButton wxMenuSubButton = new WxMenuButton();
							wxMenuSubButton.setAppId(sMenu.getAppid());
							wxMenuSubButton.setKey(sMenu.getKeyv());
							wxMenuSubButton.setMediaId(sMenu.getMediaid());
							wxMenuSubButton.setName(sMenu.getName());
							wxMenuSubButton.setPagePath(sMenu.getPagepath());
							wxMenuSubButton.setType(sMenu.getType());
							wxMenuSubButton.setUrl(sMenu.getUrl());
							subbuttons.add(wxMenuSubButton);
						}
						wxMenuButton.setSubButtons(subbuttons);
						buttons.add(wxMenuButton);
					}
					wxMenu.setButtons(buttons);
					try {
						String resultStr = weiXinConfigure.getService().getMenuService().menuCreate(wxMenu);
						if(StringUtils.isBlank(resultStr)){
							msg = "post_success";
						}
					} catch (WxErrorException e) {
						msg = e.getError().getJson();
						msg = URLEncoder.encode(msg);
						e.printStackTrace();
					}
				}else{
					msg = "post_err";
				}
			}
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/menu.html?id="+id+"&msg="+ msg));
	}


	private Map<String,Object> validPost(String id,HttpServletRequest request){
		String msg = "valid_success";
		Map<String,Object> map = new HashMap<>();
		SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
		List<WeiXinMenu> menuList = weiXinMenuRepository.findBySnsidAndOrgiOrderBySortindexAsc(snsAccount.getId(),super.getOrgi(request));
			/*1、自定义菜单最多包括3个一级菜单，每个一级菜单最多包含5个二级菜单。
				2、一级菜单最多4个汉字，二级菜单最多7个汉字，多出来的部分将会以“...”代替。
				3、创建自定义菜单后，菜单的刷新策略是，在用户进入公众号会话页或公众号profile页时
				，如果发现上一次拉取菜单的请求在5分钟以前，就会拉取一下菜单，如果菜单有更新，就会刷新客户端的菜单。
				测试时可以尝试取消关注公众账号后再次关注，则可以看到创建后的效果。*/
		List<WeiXinMenu> firstList = new ArrayList<>();
		List<WeiXinMenu> subAllList = new ArrayList<>();
		if(menuList != null && menuList.size() > 0){
			for(WeiXinMenu menu : menuList){
				if("0".equals(menu.getParentid())){
					firstList.add(menu);
						/*if(menu.getName().length() > 4){
							msg = "menu_name_err";
						}*/
				}
			}
			//最多包括3个一级菜单
			if(firstList != null && firstList.size() > 0 && firstList.size() < 4){
				for(WeiXinMenu parentMenu : firstList){
					List<WeiXinMenu> subList = new ArrayList<>();
					for(WeiXinMenu menu : menuList){
						if(parentMenu.getId().equals(menu.getParentid())){
							subList.add(menu);
								/*if(menu.getName().length() > 7){
									msg = "menu_name_err";
								}*/
							subAllList.add(menu);
						}
					}
					parentMenu.setSubList(subList);
					if(subList != null && subList.size() > 5){
						msg = "menu_num_err";
					}
				}
				for(WeiXinMenu parentMenu : firstList){
					if(parentMenu.getSubList().size() == 0 && StringUtils.isBlank(parentMenu.getType())){
						msg = "menu_type_empty";
					}
				}
			}else{
				msg = "menu_num_err";
			}
		}else{
			msg = "menu_num_err";//自定义菜单最多包括3个一级菜单，每个一级菜单最多包含5个二级菜单
		}
		map.put("msg",msg);
		map.put("list",firstList);
		return map;
	}

	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 授权第三方
	 * @param map
	 * @param request
	 * @param id
	 * @return
	 */
	@RequestMapping("/auth/add")
	@Menu(type = "weixin" , subtype = "weixin" )
	public ModelAndView authAdd(ModelMap map , HttpServletRequest request , @Valid String id) {

		String snsid= getSnsid();
		SystemConfig config = UKTools.getSystemConfig() ; 
		String redirectUrl = config.getIconstr() ;
		if(StringUtils.isBlank(redirectUrl)) {
			redirectUrl =  (config.isEnablessl() ? "https":"http") + "://" +  request.getServerName() + (request.getServerPort()==80 || request.getServerPort()==443?"":":"+request.getServerPort()) + "/";
		}
		
		redirectUrl = redirectUrl + "/admin/weixin/auth/jump.html?snsid="+snsid;

		String url = null;
		String msg = "";
		try {
			url = WechatOpenConfiguration.getInstance().getWxOpenComponentService().getPreAuthUrl(redirectUrl);
		} catch (WxErrorException e) {
			e.printStackTrace();
			if(e.getError().getErrorCode() == 61006){
				msg = "微信第三方授权未就绪，component ticket 未推送，请稍等10分钟";
			}else if(e.getError().getErrorCode() == 40013) {
				msg = "微信第三方授权配置未配置，或者配置信息有误，请确认！";
			}else{
				msg = e.getError().getErrorMsg();
			}
		}

		List<SNSAccount> snsAccountList = snsAccountRes.findBySnstypeAndOrgi(UKDataContext.ChannelTypeEnum.WEIXINTP.toString() , UKDataContext.SYSTEM_ORGI) ;
		if(snsAccountList != null &&snsAccountList.size() <= 0){
			msg = "微信第三方授权配置未配置，请先配置！";
		}
		map.addAttribute("msg",msg);
		map.addAttribute("url",url);
		return request(super.createAdminTempletResponse("/admin/channel/weixin/authAdd"));
	}

	/**
	 * 获取预授权码（pre_auth_code）
	 * @param map
	 * @param request
	 * @return
	 */
	@RequestMapping("/auth/jump")
	@Menu(type = "weixin" , subtype = "weixin" )
	public ModelAndView authJump(ModelMap map , HttpServletRequest request ,@RequestParam("auth_code") String authorizationCode,String snsid) throws WxErrorException {
		WxOpenQueryAuthResult queryAuthResult = WechatOpenConfiguration.getInstance().getWxOpenComponentService().getQueryAuth(authorizationCode);
		boolean flag = true;
		String msg = "";
		if(queryAuthResult != null){
			SNSAccount snsAccount = new SNSAccount();
			snsAccount.setAppkey(queryAuthResult.getAuthorizationInfo().getAuthorizerAppid());
			snsAccount.setAuthaccesstoken(queryAuthResult.getAuthorizationInfo().getAuthorizerAccessToken());
			snsAccount.setRefreshtoken(queryAuthResult.getAuthorizationInfo().getAuthorizerRefreshToken());
			snsAccount.setCreatetime(new Date());
			snsAccount.setUpdatetime(new Date());
			snsAccount.setExpirestime(7200);
			snsAccount.setSnsid(snsid);
			int count = snsAccountRes.countByAppkeyAndOrgi(snsAccount.getAppkey() , super.getOrgi(request)) ;
			if(count == 0 && !StringUtils.isBlank(snsAccount.getAppkey())){

				snsAccount.setOrgi(super.getOrgi(request));
				snsAccount.setSnstype(UKDataContext.ChannelTypeEnum.WEIXIN.toString());

				snsAccount.setMoreparam("auth");//暂时使用 为 判断扫码 还是 手动创建

				snsAccountRes.save(snsAccount) ;

				mpconfig.createRouter(snsAccount) ;

				//WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsAccount.getSnsid()) ;

				WxOpenAuthorizerInfoResult result = WechatOpenConfiguration.getInstance().getWxOpenComponentService().getAuthorizerInfo(snsAccount.getAppkey());

				if(result != null ){
					snsAccount.setName(result.getAuthorizerInfo().getNickName());
					snsAccount.setHeadimg(result.getAuthorizerInfo().getHeadImg());
					snsAccount.setAccount(result.getAuthorizerInfo().getServiceTypeInfo() == 2 ? "sub":"sev");
					snsAccountRes.save(snsAccount) ;
				}
			}else{
				flag = false;
				msg = "appid_exist";
			}
		}else{
			flag = false;
			msg = "auth_error";
		}

		map.addAttribute("flag",flag);
		map.addAttribute("msg",msg);
		return request(super.createRequestPageTempletResponse("/admin/channel/weixin/authsuccess"));
	}

	/**
	 * 接收component_verify_ticket协议
	 * @param requestBody
	 * @param timestamp
	 * @param nonce
	 * @param signature
	 * @param encType
	 * @param msgSignature
	 * @return
	 */
	@RequestMapping("/auth/event")
	@ResponseBody
	public String receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
								@RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
								@RequestParam(name = "encrypt_type", required = false) String encType,
								@RequestParam(name = "msg_signature", required = false) String msgSignature) {
		this.logger.info(
				"\n接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
						+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
				signature, encType, msgSignature, timestamp, nonce, requestBody);

		if (!StringUtils.equalsIgnoreCase("aes", encType)
				|| !WechatOpenConfiguration.getInstance().getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
			throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
		}

		// aes加密的消息
		WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
				WechatOpenConfiguration.getInstance().getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
		this.logger.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
		try {
			String out = WechatOpenConfiguration.getInstance().getWxOpenComponentService().route(inMessage);
			this.logger.debug("\n组装回复信息：{}", out);
		} catch (WxErrorException e) {
			this.logger.error("receive component_verify_ticket", e);
		}


		return "success";
	}


	/**
	 * 授权第三方 配置
	 * @param map
	 * @param request
	 * @return
	 */
	@RequestMapping("/auth/config")
	@Menu(type = "weixin" , subtype = "weixin" )
	public ModelAndView authConfig(ModelMap map , HttpServletRequest request) {
		//读取 , UKDataContext.SYSTEM_ORGI
		List<SNSAccount> snsAccountList = snsAccountRes.findBySnstypeAndOrgi(UKDataContext.ChannelTypeEnum.WEIXINTP.toString() , UKDataContext.SYSTEM_ORGI) ;
		SNSAccount snsAccount = new SNSAccount();
		if(snsAccountList != null &&snsAccountList.size() > 0){
			snsAccount = snsAccountList.get(0);
		}
		map.addAttribute("snsAccount",snsAccount);

		return request(super.createAdminTempletResponse("/admin/channel/weixin/authconfig"));
	}

	@RequestMapping("/auth/config/save")
	@Menu(type = "weixin" , subtype = "weixin" )
	public ModelAndView authConfigSave(ModelMap map , HttpServletRequest request,SNSAccount snsAccount) throws NoSuchAlgorithmException {

		//NOTE 注意 第三方平台配置 使用系统租户 , UKDataContext.SYSTEM_ORGI
		SNSAccount snsAccountTemp = null;

		if(snsAccount != null && StringUtils.isNotBlank(snsAccount.getId())){
			snsAccountTemp = snsAccountRes.findByIdAndOrgi(snsAccount.getId(), UKDataContext.SYSTEM_ORGI);
			snsAccountTemp.setUpdatetime(new Date());
		}else{
			snsAccountTemp = new SNSAccount();
			snsAccountTemp.setSnstype(UKDataContext.ChannelTypeEnum.WEIXINTP.toString());
			snsAccountTemp.setOrgi( UKDataContext.SYSTEM_ORGI);
		}
		//ComponentAppId
		snsAccountTemp.setAppkey(snsAccount.getAppkey());
		if(!StringUtils.isBlank(snsAccount.getSecret())){
			snsAccountTemp.setSecret(UKTools.encryption(snsAccount.getSecret()));
		}
		snsAccountTemp.setToken(snsAccount.getToken());
		snsAccountTemp.setAeskey(snsAccount.getAeskey());

		if(StringUtils.isNotBlank(snsAccountTemp.getId())){
			List<SNSAccount> snsAccountList = snsAccountRes.findBySnstypeAndOrgi(UKDataContext.ChannelTypeEnum.WEIXINTP.toString() , UKDataContext.SYSTEM_ORGI) ;
			if(snsAccountList != null &&snsAccountList.size() > 0){
				if(!snsAccountList.get(0).getId().equals(snsAccountTemp.getId())){
					map.addAttribute("msg","只能保存一条该配置信息");
					return request(super.createRequestPageTempletResponse("redirect:/admin//weixin/auth/config"));
				}
			}
		}
		snsAccountRes.save(snsAccountTemp);

		WechatOpenConfiguration.getInstance().updateWxOpenConfig(snsAccountTemp);

		map.addAttribute("snsAccount",snsAccount);

		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/auth/config"));
	}


	/**
	 * 同步到微信
	 * @param map
	 * @param request
	 * @param id
	 * @return
	 */
	@SuppressWarnings("deprecation")
	@RequestMapping("/fans/refresh")
	@Menu(type = "weixin" , subtype = "weixin" , name = "fans")
	public ModelAndView fansRefresh(ModelMap map , HttpServletRequest request , @Valid String id) {
		String msg = "valid_success";
		if(StringUtils.isNotBlank(id)){
			SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id , super.getOrgi(request)) ;
			if("valid_success".equals(msg) && snsAccount != null){

				WeiXinConfiguration weiXinConfigure = this.mpconfig.getConfiguration(snsAccount.getSnsid()) ;

				if(weiXinConfigure != null){
					try {
						WxMpUserList wxMpUserList = null;
						String nextOpenid = null;
						do{
							wxMpUserList = weiXinConfigure.getService().getUserService().userList(nextOpenid);
							if(wxMpUserList != null && wxMpUserList.getOpenids() != null && wxMpUserList.getOpenids().size() > 0){
								//以100个为组分
								List<List<String>> openIdListList = ListUtils.partition(wxMpUserList.getOpenids(),100);
								if (openIdListList.size() > 0){
									for(List<String> list : openIdListList){
										if(list.size() > 0){
											List<WxMpUser> wxMpUsers = weiXinConfigure.getService().getUserService().userInfoList(list);
											if(wxMpUsers != null && wxMpUsers.size() > 0){
												for(WxMpUser wxUser:wxMpUsers){
													if(wxUser != null){
														List<WeiXinUser> weiXinUserList = weiXinUserRes.findByOpenidAndSnsidAndOrgi(wxUser.getOpenId() , snsAccount.getSnsid(),snsAccount.getOrgi()) ;
														WeiXinUser weiXinUser = null ;
														if(weiXinUserList.size()>0){
															weiXinUser = weiXinUserList.get(0) ;
														}else{
															weiXinUser = new WeiXinUser();
														}
														UKTools.copyProperties(wxUser, weiXinUser);
														try {
															//过滤掉 emoji表情
															weiXinUser.setNickname(UKTools.filterOffUtf8Mb4(weiXinUser.getNickname()));
														} catch (UnsupportedEncodingException e) {
															e.printStackTrace();
														}
														weiXinUser.setSex(wxUser.getSexDesc());
														weiXinUser.setSexid(wxUser.getSex());
														weiXinUser.setHeadimgurl(wxUser.getHeadImgUrl());
														weiXinUser.setOpenid(wxUser.getOpenId());
														weiXinUser.setGroupid(wxUser.getGroupId());
														weiXinUser.setSnsid(snsAccount.getSnsid());
														weiXinUser.setOrgi(snsAccount.getOrgi());
														weiXinUser.setSubscribetime(String.valueOf(wxUser.getSubscribeTime()));
														if(!StringUtils.isBlank(snsAccount.getAppkey())){
															weiXinUser.setAppid(snsAccount.getAppkey());
														}
														//if(weiXinUserRes.countByOpenidAndSnsidAndOrgi(wxUser.getOpenId(), snsAccount.getSnsid(),snsAccount.getOrgi()) == 0){
														weiXinUserRes.save(weiXinUser) ;
														/*}*/
													}
												}
											}
										}
									}
								}
								nextOpenid = wxMpUserList.getNextOpenid();
							}
						}while(StringUtils.isNotBlank(nextOpenid) && wxMpUserList != null && wxMpUserList.getOpenids() != null && wxMpUserList.getOpenids().size() > 0);

						msg = "post_success";
					} catch (WxErrorException e) {
						msg = e.getError().getJson();
						msg = URLEncoder.encode(msg);
						e.printStackTrace();
					}
				}else{
					msg = "post_err";
				}
			}
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/fans.html?id="+id+"&msg="+ msg));
	}



	@SuppressWarnings({ "resource", "deprecation" })
	@RequestMapping(value = "/media")
	@Menu(type = "weixin" , subtype = "weixin" , name = "menu")
	public void media(ModelMap map , HttpServletRequest request , HttpServletResponse response , @Valid String url ) throws IOException {
		if(StringUtils.isNotBlank(url)){

			PoolingHttpClientConnectionManager connMgr;
			RequestConfig requestConfig;
			final int MAX_TIMEOUT = 120000;


			// 设置连接池
			connMgr = new PoolingHttpClientConnectionManager();
			// 设置连接池大小
			connMgr.setMaxTotal(100);
			connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());

			RequestConfig.Builder configBuilder = RequestConfig.custom();
			// 设置连接超时
			configBuilder.setConnectTimeout(MAX_TIMEOUT);
			// 设置读取超时
			configBuilder.setSocketTimeout(MAX_TIMEOUT);
			// 设置从连接池获取连接实例的超时
			configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
			// 在提交请求之前 测试连接是否可用
			configBuilder.setStaleConnectionCheckEnabled(true);
			requestConfig = configBuilder.build();

			CloseableHttpClient httpclient = HttpClients.createDefault();
			try {
				HttpGet httpPost = new HttpGet(url);
				httpPost.setConfig(requestConfig);
				HttpResponse httpRes = httpclient.execute(httpPost);

				HttpEntity entity = httpRes.getEntity();
				if (entity != null) {
					InputStream result = entity.getContent();
					OutputStream stream = null;
					try{
						stream = response.getOutputStream();
						byte[] data = new byte[1024];
						int len = 0;
						while((len = result.read(data) ) != -1){
							stream.write(data , 0 , len);
						}
						stream.flush();
					} catch (IOException e) {
						e.printStackTrace();
					} finally{
						if(stream != null){
							try {
								stream.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}

					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}finally {
				if(httpclient!=null) {
					httpclient.close();
				}
			}
		}
	}
	

	@RequestMapping("/tips")
    @Menu(type = "weixin" , subtype = "weixin" , name = "tips")
    public ModelAndView tips(ModelMap map , HttpServletRequest request , @Valid String snsid) {
    	map.addAttribute("snsAccount", snsAccountRes.findBySnsidAndOrgi(snsid, super.getOrgi(request))) ;
    	List<SysDic> dicList = UKeFuDic.getInstance().getDic(UKDataContext.UKEFU_SYSTEM_DIC) ;
    	SysDic inputDic = null , outputDic = null ;
    	for(SysDic dic : dicList){
    		if(dic.getCode().equals(UKDataContext.UKEFU_SYSTEM_AI_INPUT)){
    			inputDic = dic ;
    		}
    		if(dic.getCode().equals(UKDataContext.UKEFU_SYSTEM_AI_OUTPUT)){
    			outputDic = dic ;
    		}
    	}
    	//NOTE 已区分租户
    	if(inputDic!=null){
    		map.addAttribute("innputtemlet", templateRes.findByTemplettypeAndOrgi(inputDic.getId(), super.getOrgi(request))) ;
    	}
    	if(outputDic!=null){
    		map.addAttribute("outputtemlet", templateRes.findByTemplettypeAndOrgi(outputDic.getId(), super.getOrgi(request))) ;
    	}
    	map.addAttribute("workDateList",UKeFuDic.getInstance().getDic("com.dic.workservice.time"));
    	map.addAttribute("workTypeList",UKeFuDic.getInstance().getDic("com.dic.workservice.worktype"));
    	
        return request(super.createAdminTempletResponse("/admin/channel/weixin/tips"));
    }
	
	@RequestMapping("/tips/save")
    @Menu(type = "weixin" , subtype = "weixin")
    public ModelAndView tips(ModelMap map , HttpServletRequest request , @Valid SNSAccount snsaccount) throws JsonProcessingException {
		if (!StringUtils.isBlank(snsaccount.getSnsid())) {
			SNSAccount old = snsAccountRes.findBySnsidAndOrgi(snsaccount.getSnsid(), super.getOrgi(request));
			if (old != null) {
				old.setSessionmsg(snsaccount.getSessionmsg());
				old.setNoagentmsg(snsaccount.getNoagentmsg());
				old.setAgentbusymsg(snsaccount.getAgentbusymsg());
				old.setSuccessmsg(snsaccount.getSuccessmsg());
				old.setFinessmsg(snsaccount.getFinessmsg());
				old.setHourcheck(snsaccount.isHourcheck());
				old.setNotinwhmsg(snsaccount.getNotinwhmsg());
				old.setSatisfaction(snsaccount.isSatisfaction());
				old.setSatisftext(snsaccount.getSatisftext());
				old.setOtherquickplay(snsaccount.isOtherquickplay());
				old.setOtherssl(snsaccount.isOtherssl());
				old.setOqrsearchurl(snsaccount.getOqrsearchurl());
				old.setOqrsearchinput(snsaccount.getOqrsearchinput());
				old.setOqrsearchoutput(snsaccount.getOqrsearchoutput());
				old.setOqrdetailurl(snsaccount.getOqrdetailurl());
				old.setOqrdetailinput(snsaccount.getOqrdetailinput());
				old.setOqrdetailoutput(snsaccount.getOqrdetailoutput());
				
				if(snsaccount.getWorkinghours() != null){
		    		List<SessionConfigItem> sessionConfigList = new ArrayList<SessionConfigItem>();
		    		String[] wk = snsaccount.getWorkinghours().split(",");
		    		for(String worktime : wk){
		    			SessionConfigItem session = new SessionConfigItem();
		    			String[] items = worktime.split(":", 3) ;
		    			session.setType(items[0]);
		    			session.setWorktype(items[1]);
		    			session.setWorkinghours(items[2]);
		    			sessionConfigList.add(session);
		    		}
		    		old.setWorkinghours(objectMapper.writeValueAsString(sessionConfigList));
		    	}else{
		    		old.setWorkinghours(null);
		    	}
				
				snsAccountRes.save(old);
			}
		}
		return request(super.createRequestPageTempletResponse("redirect:/admin/weixin/tips.html?snsid="+snsaccount.getSnsid()));
    }
}